#ifndef __MYLOGGER_H__
#define __MYLOGGER_H__

#include <iostream>
#include <string>
#include <log4cpp/Category.hh>

using std::cout;
using std::endl;
using std::string;
using std::to_string;

using namespace log4cpp;

//单例模式的特点：一个类只能创建一个对象
class Mylogger
{
public:
    static Mylogger *getInstance();
    static void destroy();

    template <typename ...Args>
	void warn(const char *msg, Args ...args)
    {
        _root.warn(msg, args...);
    }

    template <typename ...Args>
	void error(const char *msg, Args ...args)
    {
        _root.error(msg, args...);
    }

    template <typename ...Args>
	void debug(const char *msg, Args ... args)
    {
        _root.debug(msg, args...);
    }

    template <typename ...Args>
	void info(const char *msg, Args ...args)
    {
        _root.info(msg, args...);
    }

    //递归出口，应对可变参数是0个的情况
	void warn(const char *msg);
	void error(const char *msg);
	void debug(const char *msg);
	void info(const char *msg);

private:
	Mylogger();
	~Mylogger();

private:
    static Mylogger *_pInstance;
    Category &_root;//日志记录器是唯一的
};

//带参数的宏定义
#define prefix(msg) (string(__FILE__) + string(": ") \
                 + string(__FUNCTION__) + string(": ") \
                 + string(to_string(__LINE__)) + string(": ") \
                 + msg).c_str()

//__VA_ARGS__宏可以解决...的问题，
//1、
//#define MY_MACRO(format, ...) %printf(format, ##__VA_ARGS__)
//当使用 MY_MARCRO("numbers: %d, %d, %d", 1, 2, 3); 时，
//会替换成 printf("numbers: %d, %d, %d", 1, 2, 3);
//
//2、
//所以这题test.cc调用
//logError("This is wangdao message, number = %d, pstr = %s\n", number, pstr);
//替换为
//->error( prefix("This is wangdao message, number = %d, pstr = %s\n") ,number, pstr);
//而error是我们自己写的，它调用的 _root.error(msg, ...) 本身也接受可变参数
//最终变为 _root.error( prefix("This is wangdao message, number = %d, pstr = %s\n") ,number, pstr);
//也许可以认为，这个底层的error自身就和printf很像，能像printf一样使用
//
//3、
//但是如果可变参数是0个的话，那么...前面的逗号是消除不了的，所以使用的##
//相当于把 prefix(msg), 最后的这个,给去掉，否则prefix(msg,)报错
#define logError(msg, ...) \
    Mylogger::getInstance()->error(prefix(msg), ##__VA_ARGS__)

#define logInfo(msg, ...) \
    Mylogger::getInstance()->info(prefix(msg), ##__VA_ARGS__)

#define logWarn(msg, ...) \
    Mylogger::getInstance()->warn(prefix(msg), ##__VA_ARGS__)

#define logDebug(msg, ...) \
    Mylogger::getInstance()->debug(prefix(msg), ##__VA_ARGS__)

#endif








